require("bit")
require("BinTalk/struct")

ProtocolWriter = {}

function ProtocolWriter.typeDsize(v, b)
    if v <= 0X3F then
        table.insert(b, string.char(v))
    elseif v <= 0X3FFF then
        --v = v | (1 << 14);
        v = bit.bor(v, bit.lshift(1, 14))
        local v1 = bit.rshift(bit.band(v, 0XFF00), 8)
        local v2 = bit.band(v, 0XFF)
        table.insert(b, string.char(v1, v2))
    elseif v <= 0X3FFFFF then
        --v = v | (2 << 22)
        v = bit.bor(v, bit.lshift(2, 22))
        local v1 = bit.rshift(bit.band(v, 0XFF0000), 16)
        local v2 = bit.rshift(bit.band(v, 0XFF00), 8)
        local v3 = bit.band(v, 0XFF)
        table.insert(b, string.char(v1, v2, v3))
    elseif v <= 0X3FFFFFFF then
        --v = v | (3 << 30)
        v = bit.bor(v, bit.lshift(3, 30))
        local v1 = bit.rshift(bit.band(v, 0XFF000000), 24)
        local v2 = bit.rshift(bit.band(v, 0XFF0000), 16)
        local v3 = bit.rshift(bit.band(v, 0XFF00), 8)
        local v4 = bit.band(v, 0XFF)
        table.insert(b, string.char(v1, v2, v3, v4))
    end
end

function ProtocolWriter.typeInt64(v, b)
    table.insert(b, struct.pack('<l', v))
end

function ProtocolWriter.typeUint64(v, b)
    table.insert(b, struct.pack('<L', v))
end

function ProtocolWriter.typeDouble(v, b)
    table.insert(b, struct.pack('<d', v))
end

function ProtocolWriter.typeFloat(v, b)
    table.insert(b, struct.pack('<f', v))
end

function ProtocolWriter.typeInt32(v, b)
    table.insert(b, struct.pack('<i', v))
end

function ProtocolWriter.typeUint32(v, b)
    table.insert(b, struct.pack('<I', v))
end

function ProtocolWriter.typeInt16(v, b)
    table.insert(b, struct.pack('<h', v))
end

function ProtocolWriter.typeUint16(v, b)
    table.insert(b, struct.pack('<H', v))
end

function ProtocolWriter.typeInt8(v, b)
    table.insert(b, struct.pack('<b', v))
end

function ProtocolWriter.typeUint8(v, b)
    table.insert(b, struct.pack('<B', v))
end

function ProtocolWriter.typeBool(v, b)
    if v then
        table.insert(b, '\001')
    else
        table.insert(b, '\000')
    end
end

function ProtocolWriter.typeString(v, b)
    local l = #v
    ProtocolWriter.typeDsize(l, b)
    table.insert(b, v)
end

function ProtocolWriter.typeEnum(v, b)
    ProtocolWriter.typeUint8(v, b)
end

function ProtocolWriter.typeBinary(v, b)
    local l = #v
    ProtocolWriter.typeDsize(l, b)
    table.insert(b, v)
end

function ProtocolWriter.WriteMid(v, b)
    ProtocolWriter.typeUInt16(v, b)
end

function ProtocolWriter.write(t, a, v, b)
    if a then
        local l = #v
        ProtocolWriter.typeDsize(l, b)
        local i = 1
        while i <= l do
            t(v[i], b)
            i = i + 1
        end
    else
        return t(v, b)
    end
end
